package com.c2b.algorithm.leetcode.base;

/**
 * <a href="https://leetcode.cn/problems/game-of-life/">生命游戏(Game of Life)</a>
 * <p>根据 百度百科 ， 生命游戏 ，简称为 生命 ，是英国数学家约翰·何顿·康威在 1970 年发明的细胞自动机。</p>
 * <p>
 * 给定一个包含 m × n 个格子的面板，每一个格子都可以看成是一个细胞。每个细胞都具有一个初始状态： 1 即为 活细胞 （live），或 0 即为 死细胞 （dead）。
 * 每个细胞与其八个相邻位置（水平，垂直，对角线）的细胞都遵循以下四条生存定律：
 *     <ol>
 *         <li>如果活细胞周围八个位置的活细胞数少于两个，则该位置活细胞死亡；</li>
 *         <li>如果活细胞周围八个位置有两个或三个活细胞，则该位置活细胞仍然存活；</li>
 *         <li>如果活细胞周围八个位置有超过三个活细胞，则该位置活细胞死亡；</li>
 *         <li>如果死细胞周围正好有三个活细胞，则该位置死细胞复活；</li>
 *     </ol>
 * </p>
 * <p>下一个状态是通过将上述规则同时应用于当前状态下的每个细胞所形成的，其中细胞的出生和死亡是同时发生的。给你 m x n 网格面板 board 的当前状态，返回下一个状态。</p>
 *
 * <p>
 * <b>示例：</b>
 * <pre>
 * 示例 1：
 *      输入：board = [[0,1,0],[0,0,1],[1,1,1],[0,0,0]]
 *      输出：[[0,0,0],[1,0,1],[0,1,1],[0,1,0]]
 *
 * 示例 2：
 *      输入：board = [[1,1],[1,0]]
 *      输出：[[1,1],[1,1]]
 * </pre>
 * </p>
 *
 * <p>
 * <b>提示：</b>
 * <ul>
 *      <li>m == board.length</li>
 *      <li>n == board[i].length</li>
 *      <li>1 <= m, n <= 25</li>
 *      <li>board[i][j] 为 0 或 1</li>
 * </ul>
 * </p>
 *
 * <p>
 * <b>进阶：</b>
 * <ul>
 *     <li>你可以使用原地算法解决本题吗？请注意，面板上所有格子需要同时被更新：你不能先更新某些格子，然后使用它们的更新后的值再更新其他格子。</li>
 *     <li>本题中，我们使用二维数组来表示面板。原则上，面板是无限的，但当活细胞侵占了面板边界时会造成问题。你将如何解决这些问题？</li>
 * </ul>
 * </p>
 *
 * @author c2b
 * @since 2024/3/28 9:30
 */
public class LC0289GameOfLife_M {
    static class Solution {
        public void gameOfLife(int[][] board) {
            // 如果细胞原本是活细胞，现在变成死细胞，状态由1->3
            // 如果细胞原本是死细胞，现在变成活细胞，状态由0->2
            int m = board.length;
            int n = board[0].length;
            for (int currRow = 0; currRow < m; currRow++) {
                for (int currCol = 0; currCol < n; currCol++) {
                    board[currRow][currCol] = n(board, currRow, currCol, m, n);
                }
            }
            for (int i = 0; i < m; i++) {
                for (int j = 0; j < n; j++) {
                    if (board[i][j] == 2) {
                        board[i][j] = 1;
                    } else if (board[i][j] == 3) {
                        board[i][j] = 0;
                    }
                }
            }
        }

        private int n(int[][] board, int row, int col, int m, int n) {
            int liveNeighbors = 0;
            for (int i = row - 1; i <= row + 1; i++) {
                for (int j = col - 1; j <= col + 1; j++) {
                    // 去除本身
                    if (i == row && j == col) {
                        continue;
                    }
                    // 越界判断
                    if (i >= 0 && i < m && j >= 0 && j < n ) {
                        // 周围细胞的存活个数
                        int s = board[i][j];
                        if (s == 1 || s == 3) {
                            ++liveNeighbors;
                        }
                    }
                }
            }
            // 当前细胞是存活还是死亡
            if (board[row][col] == 0 && liveNeighbors == 3) {
                // 0->1：用2记录由0到1的变化
                return 2;
            } else if (board[row][col] == 1 && (liveNeighbors < 2 || liveNeighbors > 3)) {
                // 1->0：用3记录由0到1的变化
                return 3;
            }
            return board[row][col];
        }
    }

    public static void main(String[] args) {
        Solution solution = new Solution();

        int[][] e1 = {{0, 1, 0}, {0, 0, 1}, {1, 1, 1}, {0, 0, 0}};
        solution.gameOfLife(e1);
        System.out.println("////");
        int[][] e2 = {{1, 1}, {1, 0}};
        solution.gameOfLife(e2);
        System.out.println("////");
    }
}
